package main

import (
	"encoding/json"
	"fmt"
	"unsafe"
)

//类型定义
type newInt int

//类型别名
type myInt = int

/**
	区别：
	myInt 编译时不会有这种类型
	newInt是包中的newInt类型
 */
type person struct {
	name string
	city string
	age int
}

var a int


func main() {
	var a newInt
	var b myInt
	fmt.Printf("type of a: %T\n", a)
	fmt.Printf("type of b: %T\n", b)
	//实例化person
	var p person
	p.age = 19
	p.name = "haha"
	p.city = "北京"
	fmt.Printf("person %v\n", p)
	fmt.Printf("person %#v\n", p)
	//匿名结构体
	var user struct{Name string; Age int}
	user.Age = 12
	user.Name = "小米"
	fmt.Printf("%#v\n", user)
	//指针类型的结构体
	var p2 = new(person)
	p2.age = 30
	fmt.Printf("%T\n", p2)
	fmt.Printf("%#v\n", p2)
	//取结构体的地址实例化
	p3 := &person{}
	fmt.Printf("%T\n", p3)
	fmt.Printf("%#v\n", p3)
	p3.name = "七米"
	fmt.Printf("%#v\n", p3)
	p4 := person{
		name: "aaa",
		age: 18,
		city: "北京",
	}
	fmt.Printf("%#v\n", p4)
	p5 := &person{
		name: "bbb",
		age: 20,
		city: "上海",
	}
	fmt.Printf("%#v\n", p5)
	//使用值的列表初始化
	p7 := &person{
		"哈哈",
		"beijing",
		20,
	}
	fmt.Printf("%#v\n", p7)
	//结构体内存布局
	n := test{
		1,2,3,	//结构体占用一块连续的内存
	}
	fmt.Printf("a: %p\n", &n.a)
	fmt.Printf("b: %p\n", &n.b)
	fmt.Printf("c: %p\n", &n.c)

	var v struct{}	//空结构体不占用内存
	fmt.Println(unsafe.Sizeof(v))

	//面试题
	m := make(map[string]*student)
	stus := []student{
		{name: "aaa", age: 20},
		{name: "bbb", age: 30},
		{name: "ccc", age: 40},
	}

	for _, stu := range stus{
 		m[stu.name] = &stu
		fmt.Println(m[stu.name])
	}
	for k, v := range m{
		fmt.Println(k, "=>", v)
	}
	fmt.Println("==============")
	person1 := NewPerson("ye", 20)
	person1.Dream()
	person1.setAge(30)
	fmt.Println("person1", person1)
	person1.setAge(32)
	fmt.Println("person1", person1)

	pp := person1.setAge1(44)
	fmt.Println("person1", pp)

	var my MyInt
	my.sayHello()
	my = 100
	fmt.Printf("%#v %T\n", my, my)

	niming := niming{
		"ye",
		20,
	}
	fmt.Printf("%#v\n", niming)
	fmt.Println(niming.string, niming.int)

	//初始化嵌套
	User := User{
		Address: Address{
			City: "hengshui",
			Province: "hebei",
		},
		Name: "ye",
		Gender: "nan",
	}
	fmt.Printf("user1=%#v\n", User)
	niming1 := niming1{
		"叶",
		20,
		Address{ "河北", "衡水"},
	}
	fmt.Printf("niming1=%#v\n", niming1)
	fmt.Println("nimiang1.city: ", niming1.City)

	d1 := Dog{
		Feet: 4,
		Animal:Animal{"小狗"},
	}
	d1.move()
	d1.wang()

	//结构体json
	c := &Class{
		Title: "302",
		Students: make([]*Student, 0,200),
	}

	for i := 0; i < 10; i++ {
		stu := &Student{
			Name: fmt.Sprintf("stu%02d", i),
			Gender: "男",
			ID: i,
		}
		c.Students = append(c.Students, stu)
	}
	data, err := json.Marshal(c)
	if err != nil {
		fmt.Println("json marshal failed")
		return
	}
	fmt.Printf("json:%s\n", data)
	//反序列化
	//c1 := &Class{}
	var c1 Class
	err = json.Unmarshal([]byte(data), &c1)
	if err != nil {
		fmt.Println("json unmarshal failed!")
		return 
	}
	fmt.Printf("%#v\n", c1)

	s1 := stu{
		ID: 1,
		Gender: "男",
		Name: "lilei",
	}
	data, err = json.Marshal(s1)
	if err != nil {
		fmt.Println("json marshal failed!")
		return
	}
	fmt.Printf("json str : %s\n", data)

	//修改per的dream
	per1 := Per{
		name: "小王子",
		age: 20,
	}
	dreams := []string{"吃饭","睡觉"}
	per1.setDreams(dreams)
	dreams[1] = "不睡觉"
	fmt.Println(per1.dreams)	//可以修改但是做法不对

	per1.setDreams(dreams)	//正确做法

}

// Per 补充点
type Per struct {
	name string
	age int
	dreams []string
}
//修改per的dream的正确做法，返回值slice和map的也要这么处理
func (p *Per) setDreams1(dreams []string)  {
	p.dreams = make([]string, len(dreams))
	copy(p.dreams, dreams)
}
//修改per的dream
func (p *Per) setDreams(dreams []string) {
	p.dreams = dreams
}

//结构体标签
type stu struct {
	ID int `json:"id"`
	Gender string `json:"gender"`
	Name   string `json:"name"`
}

// Student 学生
type Student struct {
	ID int
	Gender string
	Name string
}

// Class 班级
type Class struct {
	Title string
	Students []*Student
}

//结构体继承

// Animal 动物
type Animal struct {
	name string
}

func (a Animal) move() {
	fmt.Printf("%s会动！\n", a.name)
}
type Dog struct {
	Animal
	Feet int
}

func (d Dog) wang() {
	fmt.Printf("%s会汪汪汪~\n", d.name)
}


//嵌套匿名字段, 字段冲突的话就只能把调用写全了
type niming1 struct {
	Name string
	Age int
	Address
}

//嵌套结构体
type Address struct {
	Province string
	City string
}
type User struct {
	Address Address
	Name string
	Gender string
}

//结构体的匿名字段
type niming struct {
	string
	int
}

// MyInt 任意类型添加方法	不可以给别的包的类型定义方法
type MyInt int

func (i MyInt) sayHello() {
	fmt.Println("Hello, 我是一个int。")
}

//为Person增加一个设置年龄的方法
func (p Person) setAge1(age int) *Person {	//值类型接受者
	p.age = age
	p1 := &p
	return p1
}
func (p *Person) setAge(age int) {	//指针类型接受者，需要修改接受者的值，用到指针类型
	p.age = age
}

type Person struct {
	name string
	age int
}

func NewPerson(name string, age int) *Person {
	return &Person{
		name: name,
		age: age,
	}
}
//Dream Person做梦的方法
func (p Person) Dream()  {
	fmt.Printf("%s的梦想是学好go语言\n", p.name)
}

//构造函数
func newPerson(name, city string, age int) *person {
	return &person{
		name: name,
		city: city,
		age: age,
	}
}


type student struct {
	name string
	age int
}

type test struct {
	a int
	b int
	c int
}
